package com.newstart.springdatajpa.project.service.serviceImpl;

import com.newstart.springdatajpa.project.model.entity.ArticleDetail;
import com.newstart.springdatajpa.project.model.vo.CrudVo;
import com.newstart.springdatajpa.project.model.dto.CrudDto;
import com.newstart.springdatajpa.project.model.entity.Article;
import com.newstart.springdatajpa.project.repository.ArticleRepository;
import com.newstart.springdatajpa.project.service.ArticleService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Currency;
import java.util.List;
import java.util.Optional;


@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleRepository articleRepository;

    //简单CRUD
    @Override
    public CrudVo crudDatebase(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        Article article = new Article();
        switch (crudDto.getCrud()){
            case "save":
                article.setTitle("文章标题");
                article.setContent("文章内容");
                vo.setArticle(articleRepository.saveAndFlush(article));
                break;
            case "deleteOne":
                articleRepository.deleteById(2);
                break;
            case "updateone"://其他字段更新为null
                article.setId(1);
                article.setTitle("更新文章标题");
                articleRepository.saveAndFlush(article);
                break;
            case "updatetwo"://只更新部分字段
                articleRepository.updateById(3);
                break;
            case "selectOne":
                vo.setArticle(articleRepository.findById(1).get());
                break;
            case "selectAll":
                vo.setArticleList(articleRepository.findAll());
                break;
        }
        return vo;
    }

    //分页兼排序
    @Override
    public CrudVo jpaPage(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        //jpa自带分页和根据字段排序(分页始0，参数始1)
        PageRequest pageable = PageRequest.of(crudDto.getPageNo()-1,5, Sort.by(Sort.Order.desc("createTime")));
        List<Article> articleList = new ArrayList<>();
        if(crudDto.getFlag()==1){
            Page<Article> allPage = articleRepository.findAll(pageable);
            vo.setArticlePage(allPage);
        }else if(crudDto.getFlag()==2){
            articleList = articleRepository.findTop5ByContent(crudDto.getArticle().getContent(), pageable);
        }else if(crudDto.getFlag()==3){
            articleList = articleRepository.findTop5ByProjectIdAndContentContains(crudDto.getArticle().getProjectId(),"%"+crudDto.getArticle().getContent()+"%",pageable);
        }else if(crudDto.getFlag()==4){
            articleList = articleRepository.findJoinOn(crudDto.getArticle().getProjectId(),pageable);
        }
        vo.setArticleList(articleList);
        return vo;
    }

    //模糊查询,findByxxxAndxxx
    @Override
    public CrudVo selectLike(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        List<Article> articleList = new ArrayList<>();
        if(crudDto.getFlag()==1){
            //like查询
            articleList = articleRepository.findByTitleLike("%" + crudDto.getArticle().getTitle() + "%");
        }else if(crudDto.getFlag()==2){
            //contains查询
            articleList = articleRepository.findByTitleContainsOrContentContains(crudDto.getArticle().getTitle(),crudDto.getArticle().getContent());
        }
        vo.setArticleList(articleList);
        return vo;
    }

    //实体类查询
    @Override
    public CrudVo jpqlselect(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        List<Article> articleList = new ArrayList<>();
        PageRequest pageable = PageRequest.of(crudDto.getPageNo(), 5, Sort.by(Sort.Order.desc("id")));
        if(crudDto.getFlag()==1){
            //?占位符
            articleList = articleRepository.selectByTitleAndContent(crudDto.getArticle().getTitle(),crudDto.getArticle().getContent());
        }else if(crudDto.getFlag()==2){
            //：占位符
            articleList = articleRepository.selectByIdAndTitle(crudDto.getArticle().getId(), crudDto.getArticle().getTitle());
        }else if(crudDto.getFlag()==3){
            //实体类占位符
            Article article = new Article();
            article.setId(12);
            article.setTitle("标题");
            articleList = articleRepository.selectByArticle(crudDto.getArticle(),pageable);
        }
        vo.setArticleList(articleList);
        return vo;
    }

    //原生sql查询
    @Override
    public CrudVo sqlselect(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        PageRequest pageable = PageRequest.of(crudDto.getPageNo(), 5, Sort.by(Sort.Order.desc("id")));
        List<Article> articleList = new ArrayList<>();
        if(crudDto.getFlag()==1){
            //原生sql查询
            articleList = articleRepository.selectBySql(crudDto.getArticle(), pageable);
        }
        vo.setArticleList(articleList);
        return vo;
    }

    //动态查询
    @Override
    public CrudVo dynamiQuery(CrudDto crudDto) {
        CrudVo vo = new CrudVo();
        List<Article> articleList = new ArrayList<>();
        if(crudDto.getFlag()==1){
            Article article = new Article();
            article.setId(crudDto.getArticle().getId());
            article.setTitle(crudDto.getArticle().getTitle());
            articleList = findBySpecification(crudDto.getArticle());
        }
        vo.setArticleList(articleList);
        return vo;
    }

    public List<Article> findBySpecification(Article article){
        List<Article> articleList = articleRepository.findAll(new Specification<Article>() {
            /**
             * 匿名内部类
             * @param root 处理实体和字段,实体和实体之间关系
             * @param criteriaQuery 对查询结果处理，比如：分组,聚合,排序,去重
             * @param criteriaBuilder 用于构造查询条件,调用sql函数
             * @return
             */
            @Override
            public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //定义一个Predicate的list用来保存我们的参数
                List<Predicate> predicateList = new ArrayList<>();
                //取出对应的属性而非值,拼接对应的参数
                Path<String> title = root.get("title");
                if (StringUtils.hasLength(article.getTitle())) {
                    Predicate predicate = criteriaBuilder.like(title, "%"+article.getTitle()+"%");
                    predicateList.add(predicate);
                }
                Path<Integer> id = root.get("id");
                if (article.getId() != 0) {
                    Predicate predicate = criteriaBuilder.gt(id, article.getId());
                    predicateList.add(predicate);
                }
                Predicate predicate = criteriaBuilder.and(predicateList.toArray(new Predicate[]{}));
                return predicate;
            }
        });
        return articleList;
    }

    //多表查询
    @Override
    public CrudVo manyTablesQuery(CrudDto crudDto) {
        CrudVo crudVo= new CrudVo();
        if(crudDto.getFlag()==1){//一对一级联检索
            Article article = articleRepository.findById(14).get();
            article.setTitle(article.getTitle());
            article.setContent(article.getArticleDetail().getContent());
            crudVo.setArticle(article);
        }else if(crudDto.getFlag()==2){//一对多级联查询
            Article article = articleRepository.findById(1).get();
            crudVo.setArticle(article);
        }
        return crudVo;
    }

}
